#include "js_mm.h"

static JS_MM *js_mm;

int js_mm_init(int max_cnt, int max_size) {
    MM_LO * mm_lo = (MM_LO *) malloc(sizeof(MM_LO)*max_cnt);
    if(NULL == mm_lo) {
        return MM_FAILE;
    }
    js_mm = (JS_MM *)malloc(sizeof(JS_MM));
    if(NULL == js_mm) {
        free(mm_lo);
        return MM_FAILE;
    }
    memset(js_mm, 0x0, sizeof(JS_MM));
    memset(mm_lo, 0x0, sizeof(MM_LO)*max_cnt);
    
    js_mm->mm_lo = mm_lo;
    js_mm->max_cnt  = max_cnt;
    js_mm->max_size = max_size;
    return MM_OK;
}

void * js_malloc(int size) {  
    void * ptr = NULL;
    MM_LO * mm_lo = NULL;
    int cnt = js_mm->max_cnt;
    uint8 flag = 0;
    while(cnt-- > 0) {
        if(IS_FREE == (mm_lo = (js_mm->mm_lo + cnt))->flag) {
            flag = 1;
            ptr = malloc(size);
            if(NULL == ptr) {
                return NULL;
            }
            js_mm->mm_cnt++;
            mm_lo->size = size;
            mm_lo->addr = ptr;
            mm_lo->flag = IS_USED;
            LOG_MM_DEBUG("index %d, free %p, flag: %d, size: %d, cnt: %d", cnt, mm_lo->addr, mm_lo->flag, mm_lo->size, js_mm->mm_cnt);
            break;
        }
    }
    if(flag == 0) {
        LOG_ERROR("Out of range, max_cnt: %d", js_mm->max_cnt);
        return NULL;
    }

    memset(ptr, 0x0, size);
    return ptr;
}

int js_free(void * ptr) {
    MM_LO * mm_lo = NULL;
    int cnt = js_mm->mm_cnt;
    uint8 flag = 0;
    while(cnt-- > 0) {
        if((mm_lo = (js_mm->mm_lo + cnt))->addr == ptr) {
            free(ptr);
            js_mm->mm_cnt--;
            LOG_MM_DEBUG("index %d, free %p, flag: %d, size: %d, cnt: %d", cnt, mm_lo->addr, mm_lo->flag, mm_lo->size, js_mm->mm_cnt);
            flag = 1;
            mm_lo->addr = NULL;
            mm_lo->flag = IS_FREE;
            mm_lo->size = 0;
            break;
        }
    }

    if(flag == 0) {
        LOG_ERROR("js_mm is not include cur ptr: %p", ptr);
        return MM_FAILE;
    }
    return KT_OK;
}

void js_mm_end() {
    int cnt = 0;
    MM_LO *mm_lo;
    if(NULL != js_mm) {
        if(NULL != js_mm->mm_lo) {
            cnt = js_mm->max_cnt;
            while(cnt-- > 0) {
                if(IS_USED == (mm_lo = (js_mm->mm_lo + cnt))->flag) { 
                    if(NULL != mm_lo->addr) {
                        free(mm_lo->addr);
                        js_mm->mm_cnt--;
                    }
                }
            }
            if(0 == js_mm->mm_cnt) {
                LOG_INFO("js_mm pool is free all successful");
            }
            free(js_mm->mm_lo);
        }
        free(js_mm);
    }
}

void print_js_mm() {
    printf("js_mm:       %p \n", js_mm);
    printf("mm_lo:       %p \n", js_mm->mm_lo);
    MM_LO * mm_lo = NULL;
    int cnt =  js_mm->max_cnt;
    while(cnt-- > 0) {
        mm_lo = js_mm->mm_lo + cnt;
        printf("mm_lo:       %p \n", mm_lo);
        printf("mm_lo->flag: %d \n", mm_lo->flag);
        printf("mm_lo->size: %d \n", mm_lo->size);
        printf("mm_lo->addr: %p \n", mm_lo->addr);
    }
}
#if MM_DEBUG
void test_js_mm() {
    LOG_INFO("test js_mm");
    if(js_mm_init(5, 1024)) {
        LOG_ERROR("mm init fail");
    }

    // print_js_mm();

    void * ptr1 = js_malloc(1024);
    LOG_DEBUG("ptr1 %p", ptr1);

    void * ptr2 = js_malloc(1024);
    LOG_DEBUG("ptr2 %p", ptr2);

    void * ptr3 = js_malloc(100);
    LOG_DEBUG("ptr3 %p", ptr3);

    void * ptr4 = js_malloc(100);
    LOG_DEBUG("ptr4 %p", ptr4);

    void * ptr5 = js_malloc(100);
    LOG_DEBUG("ptr5 %p", ptr5);

    js_free(ptr2);
    js_free(ptr3);
    js_free(ptr4);
    js_free(ptr5 + 10);

    // void * ptr7 = js_malloc(100);
    // LOG_DEBUG("ptr7 %p", ptr7);


    // print_js_mm();


    // js_free(ptr1);
    // js_free(ptr2);

    js_mm_end();
}
#endif
